package fr.idm.hudson.plugins;

import hudson.maven.MavenBuild;
import hudson.maven.MavenBuildProxy;
import hudson.maven.MavenEmbedder;
import hudson.maven.MavenReporter;
import hudson.maven.MavenReporterDescriptor;
import hudson.maven.MavenUtil;
import hudson.maven.reporters.MavenArtifact;
import hudson.maven.reporters.MavenArtifactRecord;
import hudson.model.BuildListener;
import hudson.model.Result;

import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;

import net.sf.json.JSONObject;

import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.repository.ArtifactRepositoryFactory;
import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
import org.apache.maven.project.MavenProject;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.StaplerRequest;

public class MavenSnapshotArtifactDeployer extends MavenReporter {

    private static final long serialVersionUID = 9222007385427605462L;

    public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl();

    @DataBoundConstructor
    public MavenSnapshotArtifactDeployer() {
        System.err.println("Loading Maven snapshot deployer");
    }

    @Override
    public boolean postBuild(MavenBuildProxy build, MavenProject pom, final BuildListener listener)
            throws InterruptedException, IOException {

        PrintStream logger = listener.getLogger();

        logger.println();
        logger.println("-------------------------------------------------------");
        logger.println("MAVEN SNAPSHOT ARTIFACT DEPLOYMENT");
        logger.println("-------------------------------------------------------");

        try {
            boolean isBuildSuccessful = isBuildSuccessful(build, listener);
            if (isBuildSuccessful == false) {
                listener.getLogger().println("   ... SKIPPING (build not successful)");
                return true;
            }

            logger.println("Looking for snapshot artifacts to deploy...");

            deploySnapshots(build, pom, listener, logger);
        } catch (RuntimeException e) {
            e.printStackTrace(logger);
            throw e;
        } catch (Throwable e) {
            e.printStackTrace(logger);
            throw new RuntimeException(e);
        } finally {
            logger.println("-------------------------------------------------------");
            logger.println();
        }

        return true;
    }

    private boolean isBuildSuccessful(MavenBuildProxy build, final BuildListener listener)
            throws Throwable {

        boolean res = (boolean) (Boolean) build
                .execute(new MavenBuildProxy.BuildCallable<Object, Throwable>() {

                    public Object call(MavenBuild build) throws Throwable, IOException,
                            InterruptedException {

                        Result result = build.getResult();
                        listener.getLogger().println("Build result is: " + result);
                        boolean res = result == null || result.isBetterOrEqualTo(Result.SUCCESS);
                        return res;
                    }
                });
        return res;
    }

    @SuppressWarnings( { "serial", "unchecked" })
    private void deploySnapshots(MavenBuildProxy build, final MavenProject pom,
            final BuildListener listener, final PrintStream logger) throws Throwable {

        logger.println();

        String version = pom.getVersion();
        logger.println("Found artifact '" + pom.getName() + "' with version '" + version + "'");
        if (version.contains("SNAPSHOT") == false) {
            logger.println("   ... SKIPPING (not a snapshot)");
            return;
        }

        ArtifactRepository repository = pom.getDistributionManagementArtifactRepository();
        final String repositoryId = repository.getId();
        final String repositoryUrl = repository.getUrl();
        logger.println("Distribution repository '" + repositoryId + "' with URL " + repositoryUrl);

        // POM
        final MavenArtifact pomArtifact = new MavenArtifact(pom.getGroupId(), pom.getArtifactId(),
                pom.getVersion(), null, "pom", pom.getFile().getName());
        pomArtifact.archive(build, pom.getFile(), listener);

        // main artifact
        final MavenArtifact mainArtifact = MavenArtifact.create(pom.getArtifact());
        if (mainArtifact != null) {
            File f = pom.getArtifact().getFile();
            mainArtifact.archive(build, f, listener);
        }

        // attached artifacts (if packaging is POM, this doesn't exist)
        final List<MavenArtifact> attachedArtifacts = new ArrayList<MavenArtifact>();
        for (Artifact a : (List<Artifact>) pom.getAttachedArtifacts()) {
            MavenArtifact ma = MavenArtifact.create(a);
            if (ma != null) {
                attachedArtifacts.add(ma);
                ma.archive(build, a.getFile(), listener);
            }
        }

        build.execute(new MavenBuildProxy.BuildCallable<Object, Throwable>() {

            public Object call(MavenBuild build) throws Throwable, IOException,
                    InterruptedException {

                MavenArtifactRecord mar = new MavenArtifactRecord(build, pomArtifact, mainArtifact,
                        attachedArtifacts);
                build.addAction(mar);

                MavenEmbedder embedder = MavenUtil.createEmbedder(listener, build.getProject(),
                        null);
                ArtifactRepositoryLayout layout = (ArtifactRepositoryLayout) embedder
                        .getContainer().lookup(ArtifactRepositoryLayout.ROLE, "default");
                ArtifactRepositoryFactory factory = (ArtifactRepositoryFactory) embedder
                        .lookup(ArtifactRepositoryFactory.ROLE);
                ArtifactRepository repository = factory.createDeploymentArtifactRepository(
                        repositoryId, repositoryUrl, layout, true);
                mar.deploy(embedder, repository, listener);

                return null;
            }
        });
    }

    public static final class DescriptorImpl extends MavenReporterDescriptor {

        /**
         * Do not instantiate DescriptorImpl.
         */
        private DescriptorImpl() {
            super(MavenSnapshotArtifactDeployer.class);
        }

        /**
         * {@inheritDoc}
         */
        public String getDisplayName() {
            return "Deploy maven snapshots";
        }

        public MavenReporter newInstance(StaplerRequest req, JSONObject formData)
                throws FormException {
            return req.bindJSON(MavenSnapshotArtifactDeployer.class, formData);
        }

    }
}
